#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>

#include "global.h"
#include "constantes.h"
#include "sockets.h"
#include "configuracion.h"
#include "listas.h"
#include "NIPC.h"
#include "sincronizador.h"
#include "hiloDisco.h"


extern int owner;

void * HiloDeDisco (void * pNodoDisco)
{

	fd_set set_socketsHiloParaDisco;
	int iMayorSocket = 0 ;	
	int idSinc;
	int payload;
	char *sAux=(char *)malloc(20);
	char *sNumero=(char *)malloc(20);
	disco * pDisco = (disco*) pNodoDisco;
	char buffer[512];
	char buffer_sect[20];
	char buffer_id[20];
	int flag;
	int ret;
	
	
	while(1)
	{
		
		FD_ZERO(&set_socketsHiloParaDisco);
		FD_SET(pDisco->iSocketHDAParaDA, &set_socketsHiloParaDisco);
		iMayorSocket = pDisco->iSocketHDAParaDA;	
		select(iMayorSocket + 1,&set_socketsHiloParaDisco, NULL, NULL,NULL);
		
		
		/*Recibo el IDDescriptor del pedido*/
		InfoIPC rInfoIPC;
		if(recibirIPC(pDisco->iSocketHDAParaDA,&rInfoIPC)<0){
			/*
			printf("El disco %s se ha desconectado \n",pDisco->sNombre);
			reallocateoperations(pDisco);
			return NULL;
			*/
		}
		
		if(strchr(rInfoIPC.payload, ';') != NULL)
		{
			strcpy(buffer, strtok(rInfoIPC.payload, ";"));
			strcpy(buffer_id, strtok(buffer, ","));
			strcpy(buffer_sect, strtok(NULL, "\r\n\0"));
		}
		else
			continue;

		int sector_num = atoi(buffer_sect);
		
		pedido* nodoaAtender;
		
		/******RTA DEL DISCO*******/
		if( FD_ISSET(pDisco->iSocketHDAParaDA,&set_socketsHiloParaDisco ) > 0 )	
		{
			
			if((rInfoIPC.payLoadDescriptor == RTA_READ_SECTOR_REQUEST)||(rInfoIPC.payLoadDescriptor == RTA_WRITE_SECTOR_REQUEST)){
				

				
				if(pthread_mutex_lock(&mutex)!=0){
					perror("pthread_mutex_lock");
					exit(EXIT_FAILURE);
				}
				
				
				nodoaAtender = (pedido *)BuscarDescriptorEnListaDeDisco(colaGlobal, buffer_id);
			
				if(pthread_mutex_unlock(&mutex)!=0){
					perror("pthread_mutex_unlock");
					exit(EXIT_FAILURE);
				}
				
		
				
				if(rInfoIPC.payLoadDescriptor==RTA_READ_SECTOR_REQUEST){
				
					printf("Se recibio la confirmacion de lectura del sector %s por parte del disco %s \n",buffer_sect,pDisco->sNombre);
					
					/*Le envio al cliente FSS el numero de sector respondido*/
					InfoIPC rInfoIPC3;
					rInfoIPC3.payLoadLength= strlen(buffer_sect) + 1;
					generarStructIPC(buffer_sect ,rInfoIPC.payLoadDescriptor,&rInfoIPC3);
					enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC3);
					
					
					/*Le envio al cliente FSS la data correspondiente*/
					InfoIPC rInfoIPC4;
					rInfoIPC4.payLoadLength=512;
					generarStructIPC(rInfoIPC.payload + strlen(buffer_id) + 1 + strlen(buffer_sect) + 1  ,rInfoIPC.payLoadDescriptor,&rInfoIPC4);
					enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC4);				
				
					
					if(pthread_mutex_lock(&mutex)!=0){
						perror("pthread_mutex_lock");
						exit(EXIT_FAILURE);
					}
					
					SacarNodoDescriptoresDeLista2(&nodoaAtender,&(colaGlobal),&(colaGlobal_Ult));
				
					if(pthread_mutex_unlock(&mutex)!=0){
						perror("pthread_mutex_unlock");
						exit(EXIT_FAILURE);
					}
					free(nodoaAtender);
				
					
				
					pDisco->pendings--;	
				}
				
				
				if(rInfoIPC.payLoadDescriptor==RTA_WRITE_SECTOR_REQUEST){
				
					/**************PEDIDO COMUN***************/
					
					
					/*SACO DE LISTA DE PEDIDOS DEL DISCO*/
					if(pthread_mutex_lock(&mutex)!=0){
							perror("pthread_mutex_lock");
							exit(EXIT_FAILURE);
					}
					
					SacarNodoDescriptoresDeLista2(&nodoaAtender,&(colaGlobal),&(colaGlobal_Ult));
					
					if(pthread_mutex_unlock(&mutex)!=0){
							perror("pthread_mutex_unlock");
							exit(EXIT_FAILURE);
					}
					
					/*BUSCO EN COLA DE CONTROL*/
					if(pthread_mutex_lock(&mutex2)!=0){
						perror("pthread_mutex_lock");
						exit(EXIT_FAILURE);
					}
					
					t_control *nodoCont =(t_control *)BuscarDescriptorEnColaControl(colaControl,nodoaAtender->sDescriptorID_delPedido);
					
					if(pthread_mutex_unlock(&mutex2)!=0){
						perror("pthread_mutex_unlock");
						exit(EXIT_FAILURE);
					}
				
					
					
					if(nodoCont->discosAEspejar>1)
					{

						/*ACTUALIZO DISCOS A ESPEJAR EN COLA DE CONTROL CONTROL*/
						if(pthread_mutex_lock(&mutex2)!=0){
							perror("pthread_mutex_lock");
							exit(EXIT_FAILURE);
						}
						
						nodoCont->discosAEspejar--;
						
						if(pthread_mutex_unlock(&mutex2)!=0){
							perror("pthread_mutex_unlock");
							exit(EXIT_FAILURE);
						}
						
						
					}
					else
					{					
						printf("Se recibio la confirmacion de escritura del sector %i por parte de todos los discos existentes \n",nodoaAtender->numeroSector);
						
						/*SACO DE COLA DE CONTROL*/
						if(pthread_mutex_lock(&mutex2)!=0){
							perror("pthread_mutex_lock");
							exit(EXIT_FAILURE);
						}
						
						SacarDeColaControl2(&nodoCont,&colaControl,&colaControl_Ult);
				
						if(pthread_mutex_unlock(&mutex2)!=0){
							perror("pthread_mutex_unlock");
							exit(EXIT_FAILURE);
						}
					
						free(nodoCont);
						/*Le envio al cliente FSS el numero de sector respondido*/
						InfoIPC rInfoIPC3;
						rInfoIPC3.payLoadLength= strlen(buffer_sect) + 1;
						generarStructIPC(buffer_sect ,rInfoIPC.payLoadDescriptor,&rInfoIPC3);
						enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC3);
						
						
					}
				
					pDisco->pendings--;	
					free(nodoaAtender);
				
				}
				
			}
		
			else
			{	
				printf("Recibi respuestaWTF\n");
				
				payload=WRITE_SECTORSYNC_REQUEST;
				int tamanio_buff = strlen(buffer_id) + 1 + strlen(buffer_sect) + 1 + 512 + 1;
				char * buffer2 = (char *) malloc (sizeof(char) * tamanio_buff);
				strcpy(buffer2,buffer_id);
				strcat(buffer2, ",");
				strcat(buffer2, buffer_sect);
				strcat(buffer2, ";");
				memcpy(buffer2 + strlen(buffer_id) + 1 + strlen(buffer_sect) + 1, rInfoIPC.payload + strlen(buffer_id) + 1 + strlen(buffer_sect) + 1, 512);
				InfoIPC rInfoIPC32;
				rInfoIPC32.payLoadLength=tamanio_buff;
				generarStructIPC(buffer2,payload,&rInfoIPC32);
				disco *aux=BuscarDiscoSinc();
				send(aux->iSocketHDAParaDA,rInfoIPC32.payload,530,MSG_WAITALL);
				free(rInfoIPC32.payload);
				free(buffer2);
				
			}
		
		}
	}
	
	free(sAux);
	free(sNumero);
}

void reallocateoperations(disco *dsk) {
	
	int flag,ret;
	
	SacarDeLista_DA(&dsk);
	
	printf("En reallocate operations \n");
	imprimirCola2(colaGlobal);
	printf("------------------------ \n");
	
	while(flag!=1){
		ret=pthread_mutex_trylock(&mutex);	
		if (ret==0)
		{
			pedido* lib=(pedido *)BuscarPorDisco(colaGlobal,dsk->sNombre);
			if(lib!=NULL){
				if(lib->operacion==0){
					lib->estado=0;
					asignarPedido(&lib,1);
				}
			}
			else
				flag=1;
			
			if(pthread_mutex_unlock(&mutex)!=0){
				perror("pthread_mutex_lock");
				exit(EXIT_FAILURE);
			}
		}
	}
	
	free(dsk);
	
}




int VerificarExistenciaDiscoSincronizados()
{
    struct DiscoConocido * pAuxDisco;
    int icantidad = 0;
	InfoIPC *infoIPC;
	
    pAuxDisco = ListaDiscos;
    while(pAuxDisco != NULL)
    {
	if ((pAuxDisco->Estado == LISTO)  || (pAuxDisco->Estado == SINCRONIZANDO_LEYENDO))
	    icantidad ++;
	pAuxDisco = pAuxDisco->Sgt;
    }

    return icantidad;
}


void intacad ( int n , char* cadena)
{	
    int j=0;
    int i=0;
	char aux;

	do
    {
		cadena[i] = (n % 10) + '0';    
		n=n/10;
		i++;
	}while (n > 0);

    cadena[i] = '\0';
    i--;

	while(i>j)
	{
		aux=cadena[i];
		cadena[i]=cadena[j];
		cadena[j]=aux;
		i--;
		j++;
	}

}


